package com.springboot.demo.config;

import com.springboot.demo.shiro.ShiroRealm;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.mgt.SessionsSecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * @author peter
 * @title: ShiroConfig
 * @projectName springAll-peter
 * @description: Shiro 配置类
 * @date 19-9-19上午10:24
 */
@Configuration
public class ShiroConfig {
    /**
     * 需要注意的是filterChain基于短路机制，即最先匹配原则，如：
     * <p>
     * /user/**=anon
     * /user/aa=authc 永远不会执行
     *
     * @param securityManager
     * @return
     */

    /**
     * Shiro为我们提供了一些和权限相关的注解，如下所示：
     * <p>
     * // 表示当前Subject已经通过login进行了身份验证；即Subject.isAuthenticated()返回true。
     *
     * @param securityManager
     * @return
     * @RequiresAuthentication // 表示当前Subject已经身份验证或者通过记住我登录的。
     * @RequiresUser // 表示当前Subject没有身份验证或通过记住我登录过，即是游客身份。
     * @RequiresGuest // 表示当前Subject需要角色admin和user。
     * @RequiresRoles(value={"admin", "user"}, logical= Logical.AND)
     * <p>
     * // 表示当前Subject需要权限user:a或user:b。
     * @RequiresPermissions (value = { " user : a ", " user : b " }, logical = Logical.OR)
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {

        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置securityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //登录的URL
        shiroFilterFactoryBean.setLoginUrl("/login");
        //登录成功后跳转的URL
        shiroFilterFactoryBean.setSuccessUrl("/index");
        //未授权URL
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();

        //定义filterChain,静态资源不拦截
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/fonts/**", "anon");
        filterChainDefinitionMap.put("/img/**,", "anon");

        //druid数据源监控页面不拦截
        filterChainDefinitionMap.put("/druid/**", "anon");

        //配置退出过滤器，其中具体的退出代码shiro已经替我们实现了
        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/", "anon");
        //除上意外所有URL都必须认证通过才可以访问，未通过认证自动访问LoginURL
        /**
         * 修改权限配置，将ShiroFilterFactoryBean的filterChainDefinitionMap.put("/**", "authc");
         * 更改为filterChainDefinitionMap.put("/**", "user");。
         * user指的是用户认证通过或者配置了Remember Me记住用户登录状态后可访问。
         */
        //filterChainDefinitionMap.put("/**", "authc");
        filterChainDefinitionMap.put("/**", "user");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }

    /**
     * 开启注解使用
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    public SecurityManager securityManager() {
        // 配置SecurityManager，并注入shiroRealm
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(shiroRealm());
        //将cookie管理对象设置到SecurityManager中
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }

    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    @Bean
    public ShiroRealm shiroRealm() {
        // 配置Realm，需自己实现
        return new ShiroRealm();
    }

    /**
     * cookie对象
     *
     * @return
     */
    public SimpleCookie rememberMeCookie() {

        //设置cookie名称，对应login.html页面的 <input type='checkbox' name='rememberMe'/>
        SimpleCookie cookie = new SimpleCookie("rememberMe");
        //设置cookie的过期时间，单位为秒，这里为一天
        cookie.setMaxAge(86400);

        return cookie;
    }

    /**
     * cookie管理对象
     *
     * @return
     */
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        //rememberMe cookie加密的密钥
        cookieRememberMeManager.setCipherKey(Base64.getDecoder().decode("4AvVhmFLUs0KTA3Kprsdag=="));

        return cookieRememberMeManager;
    }


}
